#include "forward_socket.h"
#include <unistd.h>		// close
#include <fcntl.h>		// fcntl
#include <arpa/inet.h>	// inet_nota
#include <sstream>
#include <string>

forward_socket::forward_socket() : s(INVALID), ar(false) {

}

forward_socket::~forward_socket(){
	if (ar){
		close();
	}
}

bool forward_socket::is_valid(){
	return (s > INVALID);
}

void forward_socket::auto_release(bool val){
	ar = val;
}

void forward_socket::attach(int s){
	close();
	this->s = s;
}

int forward_socket::dettach(){
	int fd = s;
	s = INVALID;
	return fd;
}

int forward_socket::fd(){
	return s;
}

const char* forward_socket::to_string(){
	static std::string str;
	std::stringstream ss;
	ss << "socket[" << s << "]";
	str = ss.str();
	return str.c_str();
}

int forward_socket::create(TYPE type){
	close();
	switch(type){
	case TCP:
		s = socket(PF_INET, SOCK_STREAM, 0);
		break;
	case UDP:
		s = socket(PF_INET, SOCK_DGRAM, 0);
		break;
	}
	return s;
}

void forward_socket::close(){
	if (is_valid()){
		::close(s);
		s = INVALID;
	}
}

int forward_socket::nonblocking(bool enable){
	int ret = -1;
	int val = fcntl(s, F_GETFD, 0);
	if (enable){
		ret = fcntl(s, F_SETFL, val|O_NONBLOCK);
	}else{
		ret = fcntl(s, F_SETFL, val&(~O_NONBLOCK));
	}
    return ret;
}

int forward_socket::reuseaddr(bool enable){
	int on = enable ? 1 : 0;
	int ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
	return ret;
}

int forward_socket::bind(uint16_t port){
	struct sockaddr_in addr;
	addr.sin_family = PF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr("0.0.0.0");
	return ::bind(s, (struct sockaddr *)&addr, sizeof(addr));
}

int forward_socket::listen(int backlog){
	return ::listen(s, backlog);
}

int forward_socket::accept(sockaddr * addr, socklen_t* addrlen){
	return ::accept(s, addr, addrlen);
}

int forward_socket::send(const void *buf, size_t len, int flags){
	return ::send(s, buf, len, flags);
}

int forward_socket::recv(void *buf, size_t len, int flags){
	return ::recv(s, buf, len, flags);
}

int forward_socket::recvfrom(void *buf, size_t len, int flags, sockaddr *src_addr, socklen_t *addrlen){
	return ::recvfrom(s, buf, len, flags, src_addr, addrlen);
}

int forward_socket::sendto(const void *buf, size_t len, int flags, const sockaddr *dest_addr, socklen_t addrlen){
	return ::sendto(s, buf, len, flags, dest_addr, addrlen);
}

int forward_socket::connect(const struct sockaddr *addr, socklen_t addrlen){
	return ::connect(s, addr, addrlen);
}
